package net.sf.hibernate.id;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.engine.SessionImplementor;

/**
 * <p>Title: TianYi BBS</p>
 * <p>Description: TianYi BBS System</p>
 * <p>Copyright: Copyright (c) 2004</p>
 * <p>Company: LAOER.COM/TIANYISOFT.NET</p>
 * @author laoer
 * @version 6.0
 */

public class TableID {
  private int type;
  private long currentID;
  private long maxID;

  public static String tableName = "";
  public static String columnName = "";
  public static String query = "";
  public static String update = "";

  public static int INCREMENT = 15;

  private static final Log log = LogFactory.getLog(TableID.class);

  private static TableID[] managers;
  static {
    managers = new TableID[25];
    for (int i = 0; i < managers.length; i++) {
      managers[i] = new TableID(i);
    }
  }

  public TableID(int type) {
    this.type = type;
    currentID = 0l;
    maxID = 0l;
  }

  public static long nextID(int type) {
    return managers[type].nextUniqueID();
  }

  public static long nextID(int type, SessionImplementor session) throws
      java.sql.SQLException, net.sf.hibernate.HibernateException {
    return managers[type].nextUniqueID(session);
  }

  public static void setID(int type, long currentID, long maxID) {
    managers[type].setUniqueID(currentID, maxID);
  }

  public synchronized long nextUniqueID() {
    if (! (currentID < maxID)) {
      return -1;
    }
    long id = currentID;
    currentID++;
    return id;
  }

  public synchronized long nextUniqueID(SessionImplementor session) throws
      java.sql.SQLException, net.sf.hibernate.HibernateException {
    if (! (currentID < maxID)) {
      getNextBlock(session);
    }
    long id = currentID;
    currentID++;
    return id;
  }

  public synchronized void setUniqueID(long currentID, long maxID) {
    this.currentID = currentID;
    this.maxID = maxID;
  }

  private void getNextBlock(SessionImplementor session) throws
      java.sql.SQLException, net.sf.hibernate.HibernateException {
    Connection conn = session.getBatcher().openConnection();
    long result;
    int rows;

    try {
      long newID = 0l;
      do {
        PreparedStatement qps = conn.prepareStatement(query);
        try {
          qps.setInt(1, this.type);
          ResultSet rs = qps.executeQuery();
          if (!rs.next()) {
            String err =
                "could not read a hi value - you need to populate the table: " +
                tableName;
            log.error(err);
            throw new IdentifierGenerationException(err);
          }
          result = rs.getLong(1);
          rs.close();
        }
        catch (SQLException sqle) {
          log.error("could not read a hi value", sqle);
          throw sqle;
        }
        finally {
          qps.close();
        }

        PreparedStatement ups = conn.prepareStatement(update);
        try {
          newID = result + INCREMENT;
          ups.setLong(1, newID);
          ups.setInt(2, this.type);
          ups.setLong(3, result);
          rows = ups.executeUpdate();
        }
        catch (SQLException sqle) {
          log.error("could not update hi value in: " + tableName, sqle);
          throw sqle;
        }
        finally {
          ups.close();
        }
      }
      while (rows == 0);
      conn.commit();

      this.currentID = result;
      this.maxID = newID;
      //return new Integer(result);
    }
    finally {
      session.getBatcher().closeConnection(conn);
    }

  }

}
